<?php
/**
 * XML视图方案
 * 
 * 下面是一个action的定义
 * <code>
 * public function appIndex() {
 * 		$this->text = "我是中国人";
 * 		$this->array = array("a"=>1, "b"=>2, "c"=>3);
 * 		return new IModelAndXml($this, array("version"=>"1.0", "encoding"=>"gbk"));
 * 	}
 * 	</code>
 * 
 * 浏览器将输出：
 * <code>
 * <?xml version="1.0" encoding="gbk"?>
 * <data>
 * 	<text><![CDATA[我是中国人]]></text>
 * 	<array>
 * 		<a><![CDATA[1]]></a>
 * 		<b><![CDATA[2]]></b>
 * 		<c><![CDATA[3]]></c>
 * 	</array>
 * </data>
 * </code>
 * 
 * @version $Id: IModelAndXml.php 312 2008-04-23 16:29:38Z iwind $
 * @package util.mvc
 * @since 0.0.2
 */
class IModelAndXml extends IAbstractViewScheme {
	private $model;
	private $xmlOptions;
	
	/**
	 * 构造器
	 *
	 * @param mixed $model 模型
	 * @param array $xmlOptions XML选项，可以有version,encoding，默认为 array("version"=>"1.0", "encoding"=>"UTF-8")
	 */
	public function __construct($model, $xmlOptions = array()) {
		$this->model = $model;
		if (is_array($xmlOptions)) {
			$this->xmlOptions = $xmlOptions;
		}
	}
	
	/**
	 * 取得模型
	 *
	 * @return mixed
	 */
	public function &getModel() {
		return $this->model;
	}
	
	/**
	 * 取得XML选项
	 *
	 * @return array
	 */
	public function getXmlOptions() {
		return $this->xmlOptions;
	}

	/**
	 * 执行
	 *
	 */
	public function invoke() {
		$model = &$this->getModel();
		$version = "1.0";
		$encoding = "UTF-8";
		if (isset($this->xmlOptions["version"])) {
			$version = $this->xmlOptions["version"];
		}
		if (isset($this->xmlOptions["encoding"])) {
			$encoding = $this->xmlOptions["encoding"];
		}
		
		//create document
		$document = new DOMDocument($version, $encoding);
		
		//create root element
		$rootNode = $document->createElement("data");
		$document->appendChild($rootNode);
		
		if (is_object($model) && ($model instanceof IModel)) {
			$this->toXML($document, $rootNode, $model->getObjectMap());
		}
		else {
			$this->toXML($document, $rootNode, $model);
		}
		echo $document->saveXML();
	}
	
	/**
	 * 添加键值对
	 *
	 * @param mixed $key 键
	 * @param mixed $value 值
	 * @since 0.1
	 */
	public function put($key, $value) {
		$model = &$this->getModel();
		if (is_object($model)) {
			IReflection::setProperty($model, $key, $value);
		}
		else if (is_array($model)) {
			$model[$key] = $value;
		}
		else if ($model instanceof IModel) {
			$model->addObject($key, $value);
		}
	}
	
	/**
	 * 将数据转化为XML格式
	 *
	 * @param DOMDocument $document DOM文档对象
	 * @param DOMNode $node DOM节点对象
	 * @param mixed $data 数据
	 */
	private function toXML(DOMDocument $document, DOMNode $node, $data) {
		if (is_array($data) || is_object($data)) {
			foreach ($data as $k=>$v) {
				if ($this->isValidTagName($k)) {
					$childNode = $document->createElement($k);
				}
				else {
					$childNode = $document->createElement("list");
				}
				$node->appendChild($childNode);
				if (is_scalar($v)) {
					$childNode->appendChild($document->createCDATASection($v));
				}
				else {
					$this->toXML($document, $childNode, $v);
				}
			}
		}
		else if (is_scalar($data)) {
			$node->appendChild($document->createCDATASection($data));
		}
	}
	
	/**
	 * 判断标签的某个命名是否正确
	 *
	 * @param string $name 标签名称
	 * @return boolean
	 */
	private function isValidTagName($name) {
		if (is_scalar($name) && preg_match("/^[a-z_][\\w\\.\\-]*$/i", $name)) {
			return true;
		}
		return false;
	}
}

?>